#!/bin/env python
# -*- coding: utf-8 -*-

import json
import logging
import sys
import urllib2
from time import sleep
from urlparse import urljoin


class LocalException(Exception):
    def __init__(self, msg=None, reason=None, rc=-1):
        Exception.__init__(self)
        self.msg = msg
        self.reason = reason
        self.rc = rc

    def set_reason(self, value):
        self.reason = value


SUCCESS = LocalException(rc=0)
KMXURL_EX = LocalException(msg='get kmx url error', rc=2)
REST_API_EX = LocalException(msg='metadata dataservice connect error', rc=3)

URL_DT = 'field-groups/'
URL_D = 'assets/'


class KMXPlatform(object):
    def __init__(self, url):
        self.url = url if url[-1] == '/' else url + '/'
        self.header = {}
        self.addheader('Accept', 'application/json')
        self.addheader('Content-Type', 'application/json')

        self.url_d = urljoin(url, URL_D)
        self.url_dt = urljoin(url, URL_DT)
        self.dlist = []

    def addheader(self, key, value):
        self.header.__setitem__(key, value)

    def push_dt(self, metadatatype):
        response = self.get_response(url=self.url_dt, data=metadatatype)
        if response is None:
            return
        if response.code not in [201, 409]:
            logging.error('HTTP Error Code: %d, Post deviceType %s error.' % (
                response.code, metadatatype))
            return
        response_json = json.loads(response.read())
        if response_json.get('code') != 0:
            logging.error(response_json.get('message'))
            return

        dt_dict = dict(json.loads(metadatatype))
        dt_id = dt_dict.get('id')
        url = urljoin(self.url_dt, dt_id)
        count = 0
        data=None
        while count < 10:
            count += 1
            push_response = self.get_response(url)
            data = json.loads(push_response.read())
            if data.get('fieldGroup').get('status') != 'PUBLISHED':
                sleep(0.5)
                continue
            else:
                logging.info('push metadata_dt [%s] success.' % (data.get('fieldGroup').get('id')))
                break
        return data

    def update_dt(self, metadatatype):
        dt_dict = dict(json.loads(metadatatype))
        data_tmp = {'id': dt_dict.get('id'),
                    'tags': dt_dict.get('tags'),
                    'attributes': dt_dict.get('attributes')}

        url = urljoin(self.url_dt, dt_dict.get('id'))
        response = self.get_response(url=url, method='PUT', data=json.dumps(data_tmp))
        if response.code == 201:
            return True
        else:
            logging.error('HTTP Error Code: %d, Update devicetype %s error.' % (
                response.code, json.dumps(data_tmp)))
            return False

    def push_d(self, metadatadevice):
        response = self.get_response(url=self.url_d, data=metadatadevice)
        if not response:
            return
        if response.code not in [201, 409]:
            logging.error('HTTP Error Code: %d, Post device %s error.' % (
                response.code, metadatadevice))
            return
        response_json = json.loads(response.read())
        if response_json.get('code') != 0:
            logging.error(response_json.get('message'))
            return
        asset_id = response_json.get('asset').get('id')

        url = urljoin(self.url_d, asset_id)
        count = 0
        data = None
        while count < 10:
            count += 1
            push_response = self.get_response(url)
            data = json.loads(push_response.read())
            if data.get('asset').get('status') != 'PUBLISHED':
                sleep(0.5)
                continue
            else:
                logging.info('push metadata_d [%s] success. ' % (data.get('asset').get('name')))
                break
        return data

    def update_d(self, metadatadevice):
        d_dict = dict(json.loads(metadatadevice))
        data_tmp = {
            'id': d_dict.get('id'),
            'tags': d_dict.get('tags'),
            'attributes': d_dict.get('attributes'),
            'description': d_dict.get('description')
        }
        url = urljoin(self.url_d, data_tmp.get('id'))
        response = self.get_response(url=url, method='PUT', data=json.dumps(data_tmp))
        if response.code == 201:
            return True
        else:
            logging.error('HTTP Error Code: %d, Update devicetype %s error.' % (
                response.code, json.dumps(data_tmp)))
            return False

    def get_response(self, url, method=None, data=None):

        req = urllib2.Request(url=url, data=data,
                              headers=self.header)
        # if method == 'PUT':
        #     req.get_method = lambda: 'PUT'

        try:
            response = urllib2.urlopen(req, timeout=10)
        except urllib2.HTTPError, e:

            # device exist, return 409
            if e.code == 409:
                return e

            logging.error('Connect %s error, '
                          'Method: %s, '
                          'Error Code: %d, '
                          'Error message: %s.'
                          'Data: %s, ' % (
                              url, req.get_method(), e.code, e.read(), data))
        except urllib2.URLError, e:
            logging.error(
                'Connect %s error, Error reason %s' % (
                    url, e.reason))
        else:
            return response
